//
// Created by hay boy on 2022/7/14.
//

#ifndef ALGORITHMS_LZW_H
#define ALGORITHMS_LZW_H
#include <iostream>
#include <cstring>
#include <fstream>
#include "../hashing/Hash.h"

using namespace std;
int leftOver;
bool bitsLeftOver = false;
ifstream in;
ofstream out;
int DIVISOR = 4099;
HashChains<long,int> h(DIVISOR);
int MASK1 = 255,MASK2 = 15,EXCESS = 4,BYTE_SIZE = 8;
const int ALPHA = 256,MAX_CODES = 4096;
void setFiles(int argc, char* argv[]){
    char outputFile[50],inputFile[54];
    if(argc>=2){
        strcpy(inputFile,argv[1]);
    }else{
        cout<<"Enter name of file to compress"<<endl;
        cin>>inputFile;
    }
    in.open(inputFile,ios::binary);
    if(in.fail()){
        cerr<<"Cannot open "<<inputFile<<endl;
        exit(1);
    }
    strcpy(outputFile,inputFile);
    strcat(outputFile,".zzz");
    out.open(outputFile,ios::binary);
}
void output(long pcode){
    int c,d;
    if(bitsLeftOver){
        d = int(pcode&MASK1);
        c = int((leftOver<<EXCESS)|(pcode>>BYTE_SIZE));
        out.put(c);
        out.put(d);
        bitsLeftOver = false;
        cout<<c<<" "<<d<<" ";
    }else{
        leftOver = pcode&MASK2;
        c = int(pcode>>EXCESS);
        out.put(c);
        bitsLeftOver = true;
        cout<<c<<" ";
    }
}
typedef pair<const long,int> pairType;
void compress(){
    HashChains<long,int> h(DIVISOR);
    for(int i = 0;i<ALPHA;i++){
        h.insert(pairType(i,i));
    }
//    h.insert(pairType(97,0));
//    h.insert(pairType(98,1));
    int codesUsed = ALPHA;

    int c = in.get();
    if(c!=EOF){
        long pcode = c;//前缀字符
        cout<<char(c)<<endl;
        while((c=in.get())!=EOF){
            long theKey = (pcode<<BYTE_SIZE)+c;//前缀字符加新读取的字符,
            auto* thePair = h.find(theKey);
            //字典没有前缀加读取字符，就输出前缀，并加入这个词条
            //字典有这个前缀加读取字符这个词条，不输出，修改前缀，这个前缀将会在下一次输出，因为字典没有 这个前缀加一个读取字符
            if(thePair == nullptr){
                output(pcode);
                if(codesUsed<MAX_CODES){
                    h.insert(pairType((pcode<<BYTE_SIZE)|c,codesUsed++));
                }
                pcode = c;
            }else{
                pcode = thePair->second;//用来连接更多字符，直到字典中没有那个词条，然后输出前缀，并加入新的词条
            }
        }
        output(pcode);
        if(bitsLeftOver){
            out.put(leftOver<<EXCESS);
        }
    }
    out.close();
    in.close();
}
#endif //ALGORITHMS_LZW_H
